package com.gopay.bis.service.bank.impl.bcdl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;

import com.gopay.bis.service.bank.BankOrderService;
import com.gopay.bis.service.bank.failfeature.BisBankFailFeatureService;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BcdlMessage;
import com.gopay.common.domain.bank.abc.bcdl.query.res.ApQueryRes;
import com.gopay.common.domain.bank.abc.bcdl.res.NewApRes;
import com.gopay.common.domain.bank.bcdl.BcdlPacket;
import com.gopay.common.domain.bank.boc.bcdl.batch.res.TransResBatchBody;
import com.gopay.common.domain.bank.boc.bcdl.interbank.res.TransResInterBankBody;
import com.gopay.common.domain.bank.ccb.bcdl.corp.res.TransResCorpBody;
import com.gopay.common.domain.bank.ccb.bcdl.person.res.TransResPersonBody;
import com.gopay.common.domain.bank.ccb.bcdl.query.res.TransResQueryBody;
import com.gopay.common.domain.bank.ccb.bcdl.querydcc.res.TransResQueryBody6WY101;
import com.gopay.common.domain.bank.cmb.bcdl.CmbBcdlMessage;
import com.gopay.common.domain.bank.icbc.bcdl.pay.IcbcMessageData;
import com.gopay.common.domain.bank.icbc.bcdl.pay.IcbcPacketMessage;
import com.gopay.common.order.dao.CommonQueryDAO;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BaseBcdlServiceImpl {
	
	@Resource(name = "commonQueryDAO")
    private CommonQueryDAO commonQueryDAO;

    //add by zyt,2017-9-22，失败订单特征查询用到
    @Resource(name = "bisBankFailFeatureService")
    private BisBankFailFeatureService bisBankFailFeatureService;
    @Resource(name = "bankOrderService")
    private BankOrderService bankOrderService;

    private final static Logger logger = LoggerFactory.getLogger(BaseBcdlServiceImpl.class);

    @Resource(name = "autoRejectAcctExcludes")
    private Map<String,String> autoRejectAcctExcludes;

    public String getCustName(String orderId){
    	StringBuilder sql = new StringBuilder();
        sql.append(" select c.CUST_NAME, m.mer_txn_amt from cps_gen_main_order m ");
        sql.append(" left join GOPAY_ALL_CUST_INFO c on c.CUST_ID = m.pay_cust_id ");
        sql.append(" where m.gopay_order_id=:gopayOrderId ");
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("gopayOrderId", orderId);
        List<Object[]> list = commonQueryDAO.findBySql(sql.toString(), params);
        if(list == null || list.isEmpty()){
        	return null;
        }else if (null != list.get(0)[0]) {
        	return String.valueOf(list.get(0)[0]);
        }
        return null;
    }

    /**
     * add by zyt, 2017-9-21
     * 根据bcdlMessage判断该笔订单是否失败且需要做拒绝账务，根据传入订单号，判断查询不到的情况下，对单七次后才做拒绝账务
     * @param bcdlMessage
     * @param gopayOrderId
     * @return  失败需要做拒绝账务：true； 否则：false
     */
    protected boolean isNeedRefund(BcdlMessage bcdlMessage, String gopayOrderId){
    	try{
        //非空及object类型校验
        if(bcdlMessage == null || !(bcdlMessage instanceof BcdlMessage)){
            return false;
        }
        /**央行检测 要求敏感信息掩码处理 sj 2017-11-13*/
        logger.error("bcdlMessage:" + 
        		LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(bcdlMessage)));
        String bankCode = "";
        String transType = "";
        String returnCode = "";
        String dealResult = "";
        //add by zyt.2017-12-20,额外码，工行在两个码下，还有一个instrRetCode，用这个码来做是否exclude
        String extraCode = "";
        if(bcdlMessage instanceof TransResCorpBody){
            //建行对公
            TransResCorpBody transResCorpBody = (TransResCorpBody)bcdlMessage;
            returnCode = transResCorpBody.getReturnCode() == null ? "" : transResCorpBody.getReturnCode();
            dealResult = "null";
            bankCode = "CCB";
            //transType = "6W1303";
            transType = transResCorpBody.getTxCode();
        } else if(bcdlMessage instanceof TransResPersonBody){
            //建行对私
            TransResPersonBody transResPersonBody = (TransResPersonBody)bcdlMessage;
            returnCode = transResPersonBody.getReturnCode() == null ? "" : transResPersonBody.getReturnCode();
            dealResult = "null";
            bankCode = "CCB";
            //transType = "6W1303";
            transType = transResPersonBody.getTxCode();
        } else if(bcdlMessage instanceof TransResQueryBody){
            //建行查询
            TransResQueryBody transResQueryBody = (TransResQueryBody)bcdlMessage;
            returnCode = transResQueryBody.getReturnCode()==null ? "":transResQueryBody.getReturnCode();
            dealResult = transResQueryBody.getInfo()==null ? "null":transResQueryBody.getInfo().getDealResult();
            bankCode = "CCB";
            //transType = "6W1503";

            transType = transResQueryBody.getTxCode();
        }else if(bcdlMessage instanceof CmbBcdlMessage){
            //招行所有请求都返回结果类型一样
            CmbBcdlMessage cmbBcdlMessage = (CmbBcdlMessage)bcdlMessage;
            returnCode = cmbBcdlMessage.getReqStatus();
            dealResult = cmbBcdlMessage.getRetCode();
            bankCode = "CMB";
            //transType = "GetPaymentInfo";
            transType = cmbBcdlMessage.getFunName();
        } else if(bcdlMessage instanceof TransResInterBankBody){
            //中行超级网银，目前日志中为发现
            return false;
        } else if(bcdlMessage instanceof com.gopay.common.domain.bank.boc.bcdl.corp.res.TransResCorpBody){
            //中行对公
            com.gopay.common.domain.bank.boc.bcdl.corp.res.TransResCorpBody transResCorpBody =
                    (com.gopay.common.domain.bank.boc.bcdl.corp.res.TransResCorpBody)bcdlMessage;
            returnCode = transResCorpBody.getTrans().get(0).getStatus().getRspcod();
            dealResult = transResCorpBody.getTrans().get(0).getCorps().get(0).getStatus().getRspcod();
            bankCode = "BOC";
            transType = "b2e0009";

        } else if(bcdlMessage instanceof TransResBatchBody){
            //中行对私
            TransResBatchBody transResBatchBody = (TransResBatchBody)bcdlMessage;
            returnCode = transResBatchBody.getTrans().get(0).getStatus().getRspcod();
            dealResult = transResBatchBody.getTrans().get(0).getBatchs().get(0).getStatus().getRspcod();
            bankCode = "BOC";
            transType = "b2e0078";
        } else if(bcdlMessage instanceof com.gopay.common.domain.bank.boc.bcdl.query.res.TransResQueryBody){
            //中行查询
            com.gopay.common.domain.bank.boc.bcdl.query.res.TransResQueryBody transResQueryBody =
                    (com.gopay.common.domain.bank.boc.bcdl.query.res.TransResQueryBody)bcdlMessage;
            returnCode = transResQueryBody.getTrans().get(0).getStatus().getRspcod();
            dealResult = transResQueryBody.getTrans().get(0).getQuerys().get(0).getStatus().getRspcod();
            bankCode = "BOC";
            transType = "b2e0007";
        } else if(bcdlMessage instanceof NewApRes){
            //农行对公，对私
            NewApRes newApRes = (NewApRes)bcdlMessage;
            returnCode = newApRes.getRespCode();
            dealResult = "null";
            bankCode = "ABC";
            /*if(newApRes.getDcblType() == BankConstants.DCBL_PERSON) {
                //对私
                transType = "CFRT21";
            } else if(newApRes.getDcblType() == BankConstants.DCBL_CORP) {
                transType = "CFRT02";
            }*/
            transType = newApRes.getTransCode();
        } else if(bcdlMessage instanceof ApQueryRes){
            //农行查询
            ApQueryRes apQueryRes = (ApQueryRes)bcdlMessage;
            returnCode = apQueryRes.getRespCode();
            String respPrvData = apQueryRes.getCmp().getRespPrvData();
            String respCode = respPrvData.substring(respPrvData.length()-8);
            dealResult = respCode.substring(0, 4);
            bankCode = "ABC";
            //transType = "CQRT04";
            transType = apQueryRes.getTransCode();
        } else if(bcdlMessage instanceof IcbcMessageData){
            //工行单笔查询，发送
            IcbcMessageData icbcMessageData = (IcbcMessageData)bcdlMessage;
            returnCode = icbcMessageData.getRetCode();
            dealResult = icbcMessageData.getResult();
            extraCode = icbcMessageData.getInstrRetCode();
            bankCode = "ICBC";
            transType = StringUtils.isBlank(icbcMessageData.getTransCode()) ? "QPAYENT" : icbcMessageData.getTransCode();
        } else {
            logger.error("查询失败特征，未识别的返回类型，不做拒绝账务");
            return false;
        }
        logger.info("查询失败特征参数：orderId:" + gopayOrderId + ",bankCode:" + bankCode + ",transType:" + transType + ",returnCode:" + returnCode+ ",dealResult:" + dealResult);
        //add by zyt,2017-10-16,单独针对查询返回记录不存在的情况下，只有对账次数大于7次，才去判断是否需要做拒绝账务，否则。继续查询对单
        if((StringUtils.equals(bankCode, "ICBC") && StringUtils.equals(returnCode, "B0116"))
        		//add by lilili,2018-01-17建行返回您没有不确定结果的交易流水。[查询外联记录为空]
        		|| (StringUtils.equals(bankCode, "CCB") && StringUtils.equals(returnCode, "0130Z110BB22"))
            //农行的这个不存在
            // || (StringUtils.equals(bankCode, "ABC") && StringUtils.equals(returnCode, "E99999001"))
                ){
            if(StringUtils.isNotBlank(gopayOrderId)) {
                BankOrder bankOrder = bankOrderService
                        .getBankOrderById(gopayOrderId);
                if (bankOrder != null && bankOrder.getTotalCheckTimes() < 7) {
                    return false;
                }
            } else {
                logger.error("gopayOrderId为空，失败特征记录不存在情况下，对单次数校验失效");
                return false;
            }
        }
        return judgeNeedRefundByInfo(bankCode, transType, returnCode, dealResult, extraCode);
        
    	}catch(Exception e){
    		logger.error("查询失败特征异常"+e.getMessage());
    		return false;
    	}

       
    }

    /**
     * add by zyt, 2017-9-21
     * 根据几项信息判断是否需要做拒绝账务
     * @param bankCode      银行码
     * @param transType     交易类型
     * @param returnCode    报文返回码
     * @param dealResult    处理结果
     * @return      失败需要做拒绝账务：true； 否则：false
     */
    protected boolean judgeNeedRefundByInfo(String bankCode, String transType, String returnCode, String dealResult){
        if(StringUtils.isBlank(bankCode) || StringUtils.isBlank(transType) || StringUtils.isBlank(returnCode)){
            return false;
        }
        return bisBankFailFeatureService.checkIsOrderFailed(bankCode, transType, returnCode, dealResult);
    }

    /**
     * 判断是否拒绝账务，且根绝extraCode来判断是否需要排除，
     * 如排除，则不做拒绝账务
     * @param bankCode      银行码
     * @param transType     交易类型
     * @param returnCode    报文返回码
     * @param dealResult    处理结果
     * @param extraCode     额外码
     * @return
     */
    private boolean judgeNeedRefundByInfo(String bankCode, String transType, String returnCode, String dealResult,
                                          String extraCode){
        if(isExclude(bankCode, transType, returnCode,  dealResult,extraCode)){
            return false;
        } else {
            return judgeNeedRefundByInfo(bankCode,  transType,  returnCode,  dealResult);
        }
    }

    /**
     * 排除列表中是否包含
     * @param bankCode      银行码
     * @param transType     交易类型
     * @param returnCode    报文返回码
     * @param dealResult    处理结果
     * @param extraCode     额外码
     * @return              需要排除：trur，不需要排除：false
     */
    private boolean isExclude(String bankCode, String transType, String returnCode, String dealResult,
                              String extraCode){
        String curInfo = bankCode + ":" + transType  + ":" + returnCode  + ":" + dealResult  + ":" + extraCode;
        if(autoRejectAcctExcludes.containsKey(curInfo) &&
                autoRejectAcctExcludes.get(curInfo) != null
                && Boolean.valueOf(autoRejectAcctExcludes.get(curInfo))){
            logger.info("命中排除列表，此订单不做拒绝账务:{}", curInfo);
            return true;
        }
        return false;
    }
}
